<template>
  <nut-navbar :title="`你的用户ID: ${userId}`"></nut-navbar>
  <nut-divider v-if="onlineUserIds.length < 1"> 当前无用户在线 </nut-divider>
  <nut-cell v-for="id in onlineUserIds" :title="id" :key="id">
    <template #desc>
      <nut-button size="small" type="success" :disabled="isInCall" @click="startCall(id)">
        <template #icon>
          <Icon icon="ph:phone-call-fill" width="2em" height="2em"  style="color: #fff" />
        </template>
      </nut-button>
    </template>
  </nut-cell>
  <nut-overlay
      v-model:visible="showOverlay"
      :close-on-click-overlay="false"
      :overlay-style="{
        backgroundColor: 'rgba(104,104,104,1)'
      }"
  >
    <!--  视频通话  -->
    <div style="height: 100%; width: 100%" v-if="isInCall" @click="handleBackgroundClick">
      <video ref="remoteVideo"  playsinline autoplay style="width: 100%; height: 100%"></video>
      <!-- 操作按钮，使用 v-if 控制显示/隐藏 -->
      <TransitionWrapper animationType="slide-bottom">
      <nut-space v-if="isControlVisible" class="control-panel" justify="center" fill :gutter="20">
        <nut-button v-if="isInCall" type="primary" @click.stop="hangUpCall">
          <template #icon>
            <Icon icon="ph:phone-slash-fill" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
        <nut-button v-if="isInCall" :type="isMicrophoneOn ? 'success' : 'primary'" @click.stop="toggleMicrophone">
          <template #icon>
            <Icon :icon="`ph:${isMicrophoneOn ? 'microphone-fill' : 'microphone-slash-fill'}`" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
        <nut-button v-if="isInCall" :type="isCameraOn ? 'success' : 'primary'" @click.stop="toggleCamera">
          <template #icon>
            <Icon :icon="`ph:${isCameraOn ?  'camera-fill' : 'camera-slash-fill'}`" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
        <nut-button v-if="isInCall && isCameraOn" type="info" @click.stop="switchCamera">
          <template #icon>
            <Icon icon="ph:camera-rotate-fill" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
      </nut-space>
      </TransitionWrapper>
    </div>
    <!--  接听电话  -->
    <div class="overlay-body" v-if="incomingCall">
      <nut-animate type="twinkle" loop>
        来自{{incomingCallerId}}的电话
      </nut-animate>
      <div class="overlay-content">
        <nut-button type="primary" @click="rejectCall">
          <template #icon>
            <Icon icon="ph:phone-slash-fill" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
        <nut-button type="success" @click="resolveCall">
          <template #icon>
            <Icon icon="ph:phone-incoming-fill" width="2em" height="2em"  style="color: #fff" />
          </template>
        </nut-button>
      </div>
    </div>
  </nut-overlay>
  <!-- 本地视频用于拖拽 -->
  <nut-drag attract>
    <video ref="localVideo" autoplay muted style="width: 100px; height: 200px;"></video>
  </nut-drag>
  <div v-if="error" class="error">{{ error }}</div>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import { io } from 'socket.io-client';
import TransitionWrapper from './components/TransitionWrapper.vue';
import { Icon } from '@iconify/vue';
import { showToast } from '@nutui/nutui'

const generateRandomUserId = () => {
  return Math.floor(100000 + Math.random() * 900000).toString();
};

const onlineUserIds = ref([])
const isInCall = ref(false); // 是否正在通话中
const userId = generateRandomUserId(); // // 当前用户ID
const calleeId = ref(''); // 被叫方ID
const localVideo = ref(null); // 本地视频元素
const remoteVideo = ref(null); // 远程视频元素
const error = ref(null); // 错误信息
const showOverlay = ref(false); // 显示遮罩层
const incomingCall = ref(false); // 是否有来电
const incomingCallerId = ref(''); // 来电者ID
const cameras = ref([]); // 摄像头列表
const selectedCameraId = ref(''); // 选中的摄像头
const isCameraOn = ref(false); // 是否打开摄像头
const isMicrophoneOn = ref(false); // 是否打开麦克风
const isControlVisible = ref(true); // 控制操作区显示和隐藏
const socket = io('https://192.168.1.106:3000'); // 连接到信令服务器
let localStream; // 本地媒体流
let peerConnection; // RTCPeerConnection实例
let pendingCandidates = [];
let remoteStream = null;

// 配置ICE服务器
const configuration = {
  iceServers: [
    {
      urls: 'turn:192.168.1.110:3478',
      username: 'szjk',
      credential: 'szjk@123456'
    }
  ]
};

const creatConnection= () => {
  peerConnection = new RTCPeerConnection(configuration);
  console.log('------------------创建连接了')
}

// 设置远程描述后处理候选项队列
const processPendingCandidates = async () => {
  for (const candidate of pendingCandidates) {
    try {
      await peerConnection.addIceCandidate(candidate);
    } catch (e) {
      console.error('Error adding pending ice candidate', e);
    }
  }
  pendingCandidates = [];
};

// 点击触发操作区的显示和隐藏
const handleBackgroundClick = ()=> {
  // 如果摄像头是关闭状态不能隐藏
  if(!isCameraOn.value){
    if (!isControlVisible.value){
      isControlVisible.value = true
    }
    return
  }
  isControlVisible.value = !isControlVisible.value
}

// 错误处理函数
const handleError = (err) => {
  console.error('Error: ', err);
  error.value = `Error: ${err.message || err}`;
};
// 初始化麦克风和摄像头状态
const initializeMicrophoneCameraState = () => {
  if (localStream) {
    const audioTrack = localStream.getAudioTracks()[0];
    if (audioTrack) {
      isMicrophoneOn.value = audioTrack.enabled;
    }
    // 获取初始摄像头状态
    const videoTrack = localStream.getVideoTracks()[0];
    if (audioTrack) {
      isCameraOn.value = videoTrack.enabled;
    }
  }
};

// 初始化本地媒体流
const initializeLocalStream = async () => {
  if (!navigator.mediaDevices || !navigator.mediaDevices.getUserMedia) {
    handleError(new Error('mediaDevices API not supported in this browser.'));
    return;
  }

  try {
    const constraints = {
      video: { deviceId: selectedCameraId.value ? { exact: selectedCameraId.value } : undefined },
      audio: true
    };
    localStream = await navigator.mediaDevices.getUserMedia(constraints);
    localVideo.value.srcObject = localStream; // 将媒体流绑定到本地视频元素
    initializeMicrophoneCameraState()
  } catch (err) {
    handleError(err);
  }
};

// 发起呼叫
const startCall = async (id) => {
  if(calleeId.value === userId){
    showToast.warn(`不能呼叫自己`);
    return;
  }
  calleeId.value = id
  isInCall.value = true;
  showOverlay.value = true
  await getCameras() // 获取设备信息
  await initializeLocalStream(); // 确保本地流已初始化
  socket.emit('call', { calleeId: id, callerId: userId }); // 先让服务器通知对方
};

// 接受呼叫
const resolveCall = async () => {
  incomingCall.value = false; // 关闭接听对话框
  isInCall.value = true
  stopVibrate()
  socket.emit('resolveCall', { calleeId: userId, callerId: incomingCallerId.value }); // 通知对方同意接听
};

// 拒绝呼叫
const rejectCall = () => {
  incomingCall.value = false; // 关闭接听对话框
  showOverlay.value = false
  stopVibrate()
  socket.emit('rejectCall', { calleeId: userId, callerId:incomingCallerId.value }); // 通知对方拒绝接听
};
// 清理工作：关闭连接，清理视频流
const clear = () => {
  if (peerConnection) {
    peerConnection.close(); // 关闭PeerConnection
    peerConnection = null;
  }

  if (localStream) {
    localStream.getTracks().forEach(track => track.stop()); // 停止本地流的轨道
    localStream = null;
    remoteStream = null;
    localVideo.value.srcObject = null; // 清空本地视频元素
    remoteVideo.value.srcObject = null; // 清空远程视频元素
  }
  incomingCall.value = false;
  showOverlay.value = false;
  incomingCallerId.value = '';
  isInCall.value = false;
}

// 挂断呼叫
const hangUpCall = () => {
  // 通知对方挂断电话的id，呼叫方挂断时为被呼叫方的id, 被呼叫方挂断时为呼叫方的id 服务器清理通话状态
  socket.emit('hangUp', { calleeId: incomingCallerId.value || calleeId.value }); // 通知对方挂断呼叫
  clear()
};

// 获取视频输入设备（摄像头）
const getCameras = async () => {
  const devices = await navigator.mediaDevices.enumerateDevices();
  console.log('-------获取摄像头')
  const cameraDevices =  devices.filter(device => device.kind === 'videoinput').map(device => {
    let facing = 'unknown';

    // 如果设备标签包含 "front" 或 "back"，可以用来判断前置或后置
    if (device.label.toLowerCase().includes('front')) {
      facing = 'front';
    } else if (device.label.toLowerCase().includes('back')) {
      facing = 'back';
    }

    return {
      deviceId: device.deviceId,
      label: device.label,
      facingMode: facing
    };
  });
  cameras.value = cameraDevices
  if (cameras.value.length > 0) {
    selectedCameraId.value = cameras.value[0].deviceId;
  }
};

// 切换摄像头
const switchCamera = async () => {
  const camera = cameras.value.find(e => e.deviceId !== selectedCameraId.value);
  if (camera){
    selectedCameraId.value = camera.deviceId;
  }
  if (localStream) {
    // 停止当前的视频轨道
    const videoTracks = localStream.getVideoTracks();
    videoTracks.forEach(track => track.stop());
    // 保留当前的音频轨道
    const audioTrack = localStream.getAudioTracks()[0];
    // 获取新的视频流，不再获取音频流
    const newVideoStream = await navigator.mediaDevices.getUserMedia({
      video: { deviceId: { exact: selectedCameraId.value } }
    });
    if (peerConnection) {
      // 将新的视频轨道添加到 localStream
      const newVideoTrack = newVideoStream.getVideoTracks()[0];
      const sender = peerConnection.getSenders().find(s => s.track.kind === newVideoTrack.kind);
      if (sender) {
        await sender.replaceTrack(newVideoTrack);
      }
      // 更新 localStream 中的视频轨道，同时保留原有的音频轨道
      localStream.removeTrack(videoTracks[0]); // 移除旧的视频轨道
      localStream.addTrack(newVideoTrack); // 添加新的视频轨道

      if (audioTrack) {
        localStream.addTrack(audioTrack); // 确保音频轨道仍在 localStream 中
      }
    }
  }
};

// 关闭和打开麦克风
const toggleMicrophone = () => {
  if (localStream) {
    const audioTracks = localStream.getAudioTracks();
    if (audioTracks.length > 0) {
      isMicrophoneOn.value = !isMicrophoneOn.value;
      showToast.text(`麦克风已${isMicrophoneOn.value ? '开启' : '关闭'}`);
      audioTracks[0].enabled = isMicrophoneOn.value;
    }
  }
};

// 关闭和打开摄像头
const toggleCamera = () => {
  if (localStream) {
    const videoTracks = localStream.getVideoTracks();
    if (videoTracks.length > 0) {
      isCameraOn.value = !isCameraOn.value;
      showToast.text(`摄像头已${isCameraOn.value ? '开启' : '关闭'}`);
      videoTracks[0].enabled = isCameraOn.value;
    }
  }
}

let vibrateInterval;

// 开始震动
function startVibrate(duration) {
  if (navigator.vibrate) {
    console.log('---------开启震动')
    navigator.vibrate(duration);
  }
}

// 停止震动
function stopVibrate() {
  // 清除间隔和停止持续振动
  if(vibrateInterval){
    clearInterval(vibrateInterval)
  }
  if (navigator.vibrate) {
    console.log('---------关闭震动')
    navigator.vibrate(0);
  }
}

//在给定的持续时间和间隔时开始持续的振动
//假定一个数字值
function startPeristentVibrate(duration, interval) {
  vibrateInterval = setInterval(function () {
    startVibrate(duration);
  }, interval);
}

// 监听信令服务器消息
onMounted(() => {
  getCameras()
  socket.on('connect', () => {
    console.log('连接服务器成功');
    socket.emit('register', userId); // 注册当前用户ID
  });

  socket.on('disconnect', () => {
    console.log('对方已离线');
    clear(); // 断开连接时挂断呼叫
  });
  socket.on('update-user', ({newUserId, userIds}) => {
    console.log('------update-user---------')
    onlineUserIds.value = userIds.filter(id => id !== userId);
    showToast.text(`用户${newUserId}上线了`);
  });
  socket.on('update-users', ({ userIds}) => {
    console.log('------update-users---------')
    onlineUserIds.value = userIds.filter(id => id !== userId);
  });
  socket.on('delete-user', ({disconnectUserId,userIds}) => {
    console.log('delete-user');
    onlineUserIds.value = userIds.filter(id => id !== userId);
    showToast.text(`用户${disconnectUserId}离线了`);
  });

  socket.on('over-disconnect', (disconnectId) => {
    console.log('-----对方已离线----------')
    clear(); // 处理对方挂断呼叫
    showToast.warn(`用户 ${disconnectId} 已离线,请稍后再试。`);
  });
  socket.on('call', ({callerId}) => {
    console.log('---------被呼叫了', callerId)
    incomingCallerId.value = callerId; // 设置来电用户ID
    incomingCall.value = true; // 显示接听对话框
    showOverlay.value = true;
    // 震动设备
    startPeristentVibrate(1000, 2000)
  });
  socket.on('rejectCall', () => {
    console.log('对方拒绝通话申请')
    showToast.warn(`对方拒绝通话申请！`);
    clear();
  });
  // 对方同意接听电话之后开始发offer
  socket.on('resolveCall', async () => {
    try {
      creatConnection()
      localStream?.getTracks()?.forEach(track => peerConnection?.addTrack(track, localStream)); // 将本地流的轨道添加到PeerConnection

      // 处理ICE候选项
      peerConnection.onicecandidate = ({ candidate }) => {
        if (candidate) {
          socket.emit('candidate', { candidate, calleeId: calleeId.value });
        }
      };

      // 处理远程流
      peerConnection.ontrack = (event) => {
        if (event.streams && event.streams[0] && !remoteStream) {
          console.log('呼叫方处理远程流');
          console.log(remoteStream);
          remoteStream = event.streams[0];
          remoteVideo.value.srcObject = remoteStream;// 将远程流绑定到远程视频元素
        }
      };

      const offer = await peerConnection.createOffer(); // 创建Offer
      await peerConnection.setLocalDescription(offer); // 设置本地描述
      socket.emit('offer', { offer, calleeId: calleeId.value, callerId: userId }); // 发送Offer到信令服务器
    } catch (err) {
      handleError(err);
    }
  });


  socket.on('offer', async ({offer, calleeId, callerId}) => {
    console.log('---------收到了offer')
    if (!peerConnection) {
      creatConnection()
      await initializeLocalStream(); // 确保本地流已初始化
      localStream?.getTracks()?.forEach(track => peerConnection.addTrack(track, localStream)); // 将本地流的轨道添加到PeerConnection

      // 处理ICE候选项
      peerConnection.onicecandidate = ({ candidate }) => {
        if (candidate) {
          socket.emit('candidate', { candidate, calleeId: callerId });
        }
      };

      // 处理远程流
      peerConnection.ontrack = (event) => {
        if (event.streams && event.streams[0] && !remoteStream) {
          remoteStream = event.streams[0];
          remoteVideo.value.srcObject = remoteStream;// 将远程流绑定到远程视频元素
          isInCall.value = true; // 设置正在通话中
          console.log('被呼叫方处理远程流--------------');
          console.log(remoteStream)
        }
      };
      await peerConnection.setRemoteDescription(new RTCSessionDescription(offer)); // 设置远程描述
      await processPendingCandidates();
      const answer = await peerConnection.createAnswer(); // 创建Answer
      await peerConnection.setLocalDescription(answer); // 设置本地描述
      socket.emit('answer', { answer,callerId}); // 发送Answer到信令服务器
    }
  });

  socket.on('answer', async (data) => {
    console.log(data)
    try {
      if (peerConnection && data.answer && data.answer.type && data.answer.sdp) {
        const remoteDesc = new RTCSessionDescription(data.answer);
        await peerConnection.setRemoteDescription(remoteDesc);
        await processPendingCandidates();
      } else {
        console.error('Invalid answer data received:', data.answer);
      }
    } catch (error) {
      console.error('Error setting remote description:', error);
    }
  });

  socket.on('candidate', async (data) => {
    const candidate = new RTCIceCandidate(data.candidate);
    if (peerConnection.remoteDescription && peerConnection.remoteDescription.type) {
      try {
        await peerConnection.addIceCandidate(candidate);
      } catch (e) {
        console.error('Error adding received ice candidate', e);
      }
    } else {
      pendingCandidates.push(candidate);
    }
  });

  socket.on('hangUp', () => {
    console.log('-----hangUp----------')
    clear(); // 处理对方挂断呼叫
    stopVibrate()
    showToast.text(`通话结束`);
  });
  // 处理忙碌状态
  socket.on('busy', (data) => {
    showToast.warn(`用户 ${data.calleeId} 正在通话中。请稍后再试。`);
    clear();
  });
});

</script>
<style>
.error {
  color: red;
  margin-top: 10px;
}
.overlay-body {
  color: #e3e3e3;
  display: flex;
  height: 100%;
  align-items: center;
  flex-direction: column;
  justify-content: space-around;
}
.overlay-content {
  display: flex;
  width: 160px;
  height: 150px;
  border-radius: 8px;
  align-items: center;
  justify-content: space-between;
}
.control-panel{
  position: absolute;
  bottom: 40px;
}

</style>
